import {
  Scene,
  Engine,
  FreeCamera,
  Vector3,
  HemisphericLight,
  MeshBuilder,
  SceneLoader,
  AbstractMesh, //用于存储所有常见网格特性的类
  GlowLayer,
  LightGizmo,
  GizmoManager,
  Light,
  Color3,
  DirectionalLight,
  PointLight,
  SpotLight,
  ShadowGenerator,
  ArcRotateCamera,
  CubeTexture,
} from "@babylonjs/core";
import "@babylonjs/loaders";

export class XR_demo_one {
  scene: Scene;
  engine: Engine;
  watch!: AbstractMesh;
  camera!:ArcRotateCamera



  constructor(private canvas: HTMLCanvasElement) {
    this.engine = new Engine(this.canvas, true);
    this.engine.displayLoadingUI() // 开启babylon 自带加载器 loaing
    this.scene = this.CreateScene();

    this.CreateCamera();
    this.CreatePocketWatch();

    this.engine.runRenderLoop(() => {
      this.scene.render();
    });
  }


  CreateScene(): Scene {
    const scene = new Scene(this.engine); // 场景 

    const envTex = CubeTexture.CreateFromPrefilteredData('./1k.env', scene)
    envTex.gammaSpace = false //伽玛空间 (定义纹理是否包含gamma空间中的数据（除png/jpg外的大部分凹凸）。HDR纹理通常存储在线性空间中。这只会影响PBR和背景材料)
    scene.environmentTexture = envTex

    scene.createDefaultSkybox( // 创建天空盒
      envTex, //定义用作环境纹理的纹理
      true, //默认值为false，要求使用StandardMaterial，而必须使用true PBRMaterial
      1000, //定义skybox的总体比例
      0.25 //仅当pbr为true时可用，默认值为0，无模糊，最大值为1
    )
    return scene;
  }
  CreateCamera(): void {
    this.camera = new ArcRotateCamera( //轨道式相机。(该相机总是指向给定的目标位置，并且可以以目标为旋转中心围绕该目标旋转。它可以用光标和鼠标控制，也可以用触摸事件控制。把这个相机想象成一个绕其目标位置运行的相机，或者更具想象力地想象成一颗绕地球运行的间谍卫星。它相对于目标（地球）的位置可以通过三个参数设置，α（弧度）是纵向旋转，β（弧度）为横向旋转，半径是距离目标位置的距离。)
      'camera', //name  名称
     -Math.PI /2, //alpha 定义相机沿纵轴的旋转
      Math.PI /2, // beta  定义相机沿横轴的旋转
      40, // radius 定义摄影机与其目标的距离
      Vector3.Zero(), //target  定义摄影机目标 (Vector3.Zero():三维向量都是0点)
      this.scene // 添加到场景中
    )
    this.camera.attachControl(this.camera,true) //将输入控件附加到特定的dom元素以从中获取输入。
    this.camera.wheelPrecision =300 ; // 获取或设置鼠标滚轮精度或相机缩放的速度。
    this.camera.minZ =0.07 //定义相机可以看到的最小距离。值得注意的是，深度缓冲区并不是无限的，它开始得越近，场景就越可能遇到深度对抗问题。(距离物体最近的剪辑距离)
    this.camera.lowerRadiusLimit =0.1 ; //摄像机到目标的最小允许距离（摄像机无法靠近）。这有助于限制摄影机在场景中的移动方式。
    this.camera.upperRadiusLimit =5; //摄像机与目标之间允许的最大距离（摄像机无法进一步移动）。这有助于限制摄影机在场景中的移动方式。

    this.camera.panningSensibility =0 ; //获取或设置指针平移灵敏度或相机移动的速度。 (0 相当于禁止指针平移)
    // this.camera.useBouncingBehavior =true //定义是否在摄影机上启用摄影机的反弹行为。(鼠标滚动滚动最大值或者最小值操作设置的lowerRadiusLimit、upperRadiusLimit 自动滚到设置位置)

    this.camera.useAutoRotationBehavior = true //定义是否在摄影机上启用摄影机的自动旋转行为。
    if(this.camera && this.camera.autoRotationBehavior){ //获取相机的自动旋转行为（如果已启用）。
      this.camera.autoRotationBehavior.idleRotationSpeed =.5 // 自动旋转行为 的速度
      this.camera.autoRotationBehavior.idleRotationSpinupTime =1000; //设置旋转到完全怠速转速所需的时间（毫秒）。获取旋转到完全怠速转速所需的时间（毫秒）。（从0~加速到idleRotationSpeed 的值 1 的时间 ）
      this.camera.autoRotationBehavior.idleRotationWaitTime =2000 //设置用户交互后相机开始旋转之前等待的时间（以毫秒为单位）。获取在用户交互之后摄像机开始旋转之前等待的时间（毫秒）。
      this.camera.autoRotationBehavior.zoomStopsAnimation =true ; // 设置指示用户缩放是否应停止动画的标志。获取指示用户缩放是否应停止动画的标志。 （滚动滚轮，动画立刻停止）
    }

    this.camera.useFramingBehavior = true //定义是否在摄影机上启用摄影机的取景行为。 需要配合 this.camera.setTarget(  meshes[1] ) 传入取景的模型
    if(this.camera.framingBehavior){ //框架行为（FramingBehavior）设计用于在ArcRotateCamera的目标设置为网格时自动定位它。如果希望防止摄影机位于虚拟水平面下，该选项也很有用。
      this.camera.framingBehavior.radiusScale =2 //设置应用于半径的比例（默认情况下为1）获取应用于该半径的比例
      this.camera.framingBehavior.framingTime =4000 //设置网格成帧时的过渡时间（以毫秒为单位）获取网格成帧的过渡时间
    }
    
  }

  async CreatePocketWatch(): Promise<void> {
    const { meshes } = await SceneLoader.ImportMeshAsync(
      "",
      './', 'SM_SJ_1.glb'
    );
    this.watch = meshes[0]

    // meshes[1].showBoundingBox = true //获取或设置一个布尔值，该布尔值指示是否也必须呈现边界框（默认情况下为false）
    // meshes[2].showBoundingBox = true
    // meshes[3].showBoundingBox = true
   this.camera.setTarget( meshes[2])
 
    this.engine.hideLoadingUI() // 关闭 babylon 自带的加载器 loading


  }



}